package zdream.pmfield.stage.control;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import zdream.pmfield.data.foe.Foe;
import zdream.pmfield.data.foe.MoveTargetType;
import zdream.pmfield.data.foe.MoveTemplate;
import zdream.pmfield.stage.IController;
import zdream.pmfield.stage.Stage;
import zdream.pmfield.stage.StageWrapper;
import zdream.pmfield.stage.action.AttackAction;
import zdream.pmfield.stage.action.StageAction;
import zdream.pmfield.stage.message.ActionRequestMessage;
import zdream.pmfield.stage.message.ActionRequestReply;
import zdream.pmfield.stage.object.FoeActor;
import zdream.pmfield.stage.object.StageMove;

/**
 * @author Zdream
 * @date 2023-12-16
 * @since 0.0.1
 */
public class DefaultController implements IController {
	private final StageWrapper wrapper;
	private Consumer<AttackAction> actionChecker;
	private MoveTemplate useMove;
	private Foe targetFoe;
	private boolean dazeWhenEnemiesNotFound;

	public DefaultController(StageWrapper wrapper) {
		this.wrapper = Objects.requireNonNull(wrapper);
	}

	@Override
	public ActionRequestReply createReply(ActionRequestMessage request) {
		final ActionRequestReply replyTemplate = request.createReplyTemplate();
		AttackAction action = replyTemplate.createAttackAction();
		replyTemplate.action = handle(request, action);

		if (actionChecker != null && replyTemplate.action == action) {
			//  && replyTemplate.action == action 保证 action 不是 DazeAction
			actionChecker.accept(action);
		}

		return replyTemplate;
	}

	private StageAction handle(ActionRequestMessage request, AttackAction action) {
		final Stage stage = wrapper.stage;

		// 选择技能
		StageMove move = null;
		if (useMove != null) {
			move = action.foe.findMove(useMove);
		} else {
			final ArrayList<StageMove> moves = new ArrayList<>(action.foe.attackMoves);
			for (StageMove candidateMove: moves) {
				if (action.foe.hasEnoughActionPointsForMove(candidateMove)) {
					move = candidateMove;
					break;
				}
			}
		}
		if (move == null) {
			return buildDazeAction(action);
		}
		action.move = move;

		// 选择目标
		FoeActor targetFoe = findTargetFoe(action, move);
		if (targetFoe == null) {
			return buildDazeAction(action);
		}

		action.targetFoe = targetFoe;
		action.targetSeat = targetFoe.seat;

		// 如果不在发动范围, 只能移动了
		if (move.target.type != MoveTargetType.SELF) {
			if (!stage.enableDistanceCheck) {
				return action;
			}

			int distance = action.foe.seat.distance(targetFoe.seat);
			if (move.target.isValidDistance(distance)) {
				return action;
			}

			// 看看有没有移动力了, 还有是否限制移动
			if (action.foe.movePoint == 0 || !request.movable) {
				return buildDazeAction(action);
			}

			StageMove moveToMove = action.foe.findMoveToMove();
			Set<Integer> validXs = new HashSet<>();

			for (int i : move.target.range) {
				validXs.add(targetFoe.seat.x + i);
				validXs.add(targetFoe.seat.x - i);
			}
			validXs.removeIf(validX -> Arrays.stream(stage.seats)
					.noneMatch(seat -> seat.x == validX));
			if (validXs.isEmpty()) {
				// 那你只能选择跳过了
				return buildDazeAction(action);
			}

			// 在 validXs 中选择一个离自己最近的
			final int currentX = action.foe.seat.x;
			int delta = Integer.MAX_VALUE;
			int targetX = validXs.iterator().next();
			for (Integer x : validXs) {
				int delta0 = Math.abs(x - currentX);
				if (delta0 < delta) {
					delta = delta0;
					targetX = x;
				}
			}

			action.move = moveToMove;
			action.targetFoe = null;
			action.targetSeat = targetX > currentX ? action.foe.seat.right : action.foe.seat.left;
		}

		return action;
	}

	private StageAction buildDazeAction(AttackAction action) {
		action.move = action.foe.findSkipTurnMove();
		action.targetFoe = null;
		action.targetSeat = null;
		return action;
	}

	private FoeActor findTargetFoe(AttackAction action, StageMove move) {
		final Stage stage = wrapper.stage;
		if (targetFoe != null) {
			final FoeActor foeActor = stage.findFoe(targetFoe);
			if (foeActor.seat == null && !dazeWhenEnemiesNotFound) {
				throw new RuntimeException("指示的 targetFoe: " + targetFoe + " 已经不在场了!");
			}
			return foeActor;
		}

		if (move.target.type == MoveTargetType.ENEMY || move.target.type == MoveTargetType.SEAT) {
			final List<FoeActor> candidates = stage.allFoes.stream()
					.filter(foe -> foe.side != action.foe.side)
					.filter(foe -> foe.seat != null)
					.collect(Collectors.toList());
			if (candidates.isEmpty()) {
				if (dazeWhenEnemiesNotFound) {
					return null;
				}
				throw new RuntimeException("stage 里面已经找不到技能 " + move + " 的目标了!");
			}

			int x = action.foe.seat.x;
			return Collections.min(candidates,
					Comparator.comparingInt(foe -> Math.abs(x - foe.seat.x)));
		} else if (move.target.type == MoveTargetType.SELF) {
			return action.foe;
		} else {
			throw new RuntimeException("StageWrapper 不知道如何处理目标为 " + move.target + " 的技能");
		}
	}

	public DefaultController withActionChecker(Consumer<AttackAction> checker) {
		this.actionChecker = checker;
		return this;
	}

	public DefaultController withMove(MoveTemplate move) {
		this.useMove = move;
		return this;
	}

	public DefaultController withTargetFoe(Foe targetFoe) {
		this.targetFoe = targetFoe;
		return this;
	}

	public DefaultController enableDazeWhenTargetFoeNotFound() {
		this.dazeWhenEnemiesNotFound = true;
		return this;
	}

	public DefaultController disableDazeWhenTargetFoeNotFound() {
		this.dazeWhenEnemiesNotFound = false;
		return this;
	}

	public DefaultController clearActionChecker() {
		this.actionChecker = null;
		return this;
	}

	@Override
	public String toString() {
		return "默认 AI";
	}
}
